using System;
using System.IO;
using System.Collections;

namespace NCover
{
	///<summary>
	/// A class to record which Coverage Points have been reached.
	///</summary>
	public class NCoverCheck 
	{
		///<summary>
		///Only public for testing purposes...
		///</summary>
		public static bool[] covered
		{
			get 
			{
				//get full size of bool array needed...
				int max = 0;
				foreach ( int x in _covered.Keys )
				{
					max = Math.Max(max, x);
				}

				bool [] results = new bool [ max ];
				foreach ( int x in _covered.Keys )
				{
					results[x - 1] = true;
				}
				return results;
			}
		}

		private static Hashtable _covered = new Hashtable();

		public const string DESTINATION_FILENAME =  "actual.xml";

		public static void ResetForTests()
		{
			_covered = new Hashtable();
		}

		///<summary>
		/// Instrumented code calls here to notify that a coverage point has been called.
		/// Must always return true.
		///</summary>
		public static bool Add(int point)
		{
			//Has this coverage point already been hit?
			if (_covered.ContainsKey(point))
				return true;


			//we should do this synchronusly as other wise we could have file access problems...
			lock(typeof(NCoverCheck))
			{
				//Save point to disk:
				if (!File.Exists(DESTINATION_FILENAME))
				{
					using (TextWriter writer = new StreamWriter(DESTINATION_FILENAME, false))
					{
						writer.WriteLine("<?xml version='1.0' encoding='utf-8'?><Coverage  xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' Type='actualCoverage'><CoveragePoints>");
						writer.WriteLine(String.Format("\t<CoveragePoint AbsoluteNumber='{0}' />", point));
						writer.Flush();
					}
				}
				else
				{
		//			bool written = false;
		//			while (!written)
					{
						try
						{
							using (TextWriter writer = new StreamWriter(DESTINATION_FILENAME, true))
							{
								writer.WriteLine(String.Format("\t<CoveragePoint AbsoluteNumber='{0}' />", point));
								writer.Flush();
//								written = true;
							}
						}
						catch (IOException ioe)
						{
							//file in use...
							System.Diagnostics.Debug.WriteLine(ioe.Message + " while trying to add point " + point);
							//System.Threading.Thread.SpinWait(20);
							//System.Threading.Thread.Sleep(100);
						}
					}
				}
			}

			//Indicate coverage
			_covered[point] = point;

			return true;
		}
	} 

	///<summary>
	/// A carbon copy of the above for tests to run while coverage is upon them...
	///</summary>
	public class NCoverCheckTest 
	{
		///<summary>
		///Only public for testing purposes...
		///</summary>
		public static bool[] covered
		{
			get 
			{
				//get full size of bool array needed...
				int max = 0;
				foreach ( int x in _covered.Keys )
				{
					max = Math.Max(max, x);
				}

				bool [] results = new bool [ max ];
				foreach ( int x in _covered.Keys )
				{
					results[x - 1] = true;
				}
				return results;
			}
		}

		private static Hashtable _covered = new Hashtable();

		public const string DESTINATION_FILENAME =  "actual.xml";

		public static void ResetForTests()
		{
			_covered = new Hashtable();
		}

		///<summary>
		/// Instrumented code calls here to notify that a coverage point has been called.
		/// Must always return true.
		///</summary>
		public static bool Add(int point)
		{
			//Has this coverage point already been hit?
			if (_covered.ContainsKey(point))
				return true;


			//we should do this synchronusly as other wise we could have file access problems...
			lock(typeof(NCoverCheck))
			{
				//Save point to disk:
				if (!File.Exists(DESTINATION_FILENAME))
				{
					using (TextWriter writer = new StreamWriter(DESTINATION_FILENAME, false))
					{
						writer.WriteLine("<?xml version='1.0' encoding='utf-8'?><Coverage  xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' Type='actualCoverage'><CoveragePoints>");
						writer.WriteLine(String.Format("\t<CoveragePoint AbsoluteNumber='{0}' />", point));
						writer.Flush();
					}
				}
				else
				{
					//			bool written = false;
					//			while (!written)
				{
					try
					{
						using (TextWriter writer = new StreamWriter(DESTINATION_FILENAME, true))
						{
							writer.WriteLine(String.Format("\t<CoveragePoint AbsoluteNumber='{0}' />", point));
							writer.Flush();
							//								written = true;
						}
					}
					catch (IOException ioe)
					{
						//file in use...
						System.Diagnostics.Debug.WriteLine(ioe.Message + " while trying to add point " + point);
						//System.Threading.Thread.SpinWait(20);
						//System.Threading.Thread.Sleep(100);
					}
				}
				}
			}

			//Indicate coverage
			_covered[point] = point;

			return true;
		}
	} 
}
